package com.xiaou.config;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;

import javax.servlet.Filter;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.codec.Base64;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
 * 配置shiro
 * @author xiaou
 *
 */
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import com.google.code.kaptcha.Producer;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import com.xiaou.realm.MyHashedCredentialsMatcher;
import com.xiaou.realm.UserRealm;
import com.xiaou.realm.VerificationCodeAuthenticationFilter;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
@Configuration
public class ShiroConfiguration {
	
	
	/**
	 * 定义 shiro filter 的工厂类
	 * @param securityManager
	 * @return
	 */
	@Bean
	public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
		
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		// 将过滤器绑定SecurityManager
		shiroFilterFactoryBean.setSecurityManager(securityManager);
		
		
		// 自定义过滤器
		Map<String, Filter> filters = new HashMap<>();
		VerificationCodeAuthenticationFilter verificationCodeAuthenticationFilter = new  VerificationCodeAuthenticationFilter();
		// 配置自定义过滤器的名字为vCode
		filters.put("vcode", verificationCodeAuthenticationFilter);
		Map<String,String> filterChainMap = new LinkedHashMap<>();
		shiroFilterFactoryBean.setFilters(filters);
		
		
		// 配置url过滤器
		filterChainMap.put("/", "anon");
		filterChainMap.put("/", "anon");
		filterChainMap.put("/verifyLogin", "anon");
		filterChainMap.put("/startCaptcha", "anon");
		filterChainMap.put("/js/**", "anon");
		filterChainMap.put("/css/**", "anon");
		filterChainMap.put("/img/**", "anon");
		filterChainMap.put("/toLogin", "anon");
		filterChainMap.put("/login", "vcode,anon");
		filterChainMap.put("/captcha", "anon");
		filterChainMap.put("/logout", "logout");
		filterChainMap.put("/users/info", "authc");
		filterChainMap.put("/**","user");
		// 设置默认登陆的URL
		shiroFilterFactoryBean.setLoginUrl("/toLogin");
		// 设置登陆成功后跳转的页面
		//shiroFilterFactoryBean.setSuccessUrl("/index");
		// 设置未授权的URL
		shiroFilterFactoryBean.setUnauthorizedUrl("/unauthor");
		
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
		return shiroFilterFactoryBean;
	}
	
	/**
	 * 定义shiro的安全管理器
	 * @return
	 */
	@Bean
	public SecurityManager securityManager () {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		// 注入自定义的Realm
		securityManager.setRealm(userRealm());
		// 注入EhCache缓存
		securityManager.setCacheManager(cacheManager());
		// 注入 RememberMe cookie管理器
		securityManager.setRememberMeManager(rememberMeManager());
		return securityManager;
	}
	
	@Bean
	public UserRealm userRealm() {
		 UserRealm userRealm = new UserRealm();
		 userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
		 return userRealm;
	}
	
	/**
	 * 配置密码加密策略
	 * @return
	 */
	@Bean 
	public HashedCredentialsMatcher hashedCredentialsMatcher() {
		//HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
		MyHashedCredentialsMatcher hashedCredentialsMatcher = new MyHashedCredentialsMatcher(cacheManager());
		
		// 设置加密类型
		hashedCredentialsMatcher.setHashAlgorithmName("md5");
		// 散列次数
		hashedCredentialsMatcher.setHashIterations(2);
		return hashedCredentialsMatcher;
	}
	
	/**
	 * 开启AOP注解支持
	 */
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		attributeSourceAdvisor.setSecurityManager(securityManager);
		return attributeSourceAdvisor;
	}
	@Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }
	
	/**
	 * ehcache 缓存设置
	 */
	@Bean
	public EhCacheManager cacheManager () {
		EhCacheManager enCacheManager = new EhCacheManager();
		enCacheManager.setCacheManagerConfigFile("classpath:config/ehcache.xml");
		return enCacheManager;
	}
	
	 
	 @Bean
	 public SimpleCookie rememberMeCookie(){
	       //System.out.println("ShiroConfiguration.rememberMeCookie()");
	       //这个参数是cookie的名称，对应前端的checkbox的name = rememberMe
	       SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
	       //<!-- 记住我cookie生效时间30天 ,单位秒;-->
	       simpleCookie.setMaxAge(259200);
	       return simpleCookie;
	 }

	 /**
	   * cookie管理对象;
	   * rememberMeManager()方法是生成rememberMe管理器，而且要将这个rememberMe管理器设置到securityManager中
	   * @return
	  */
	 @Bean
	 public CookieRememberMeManager rememberMeManager(){
	       //System.out.println("ShiroConfiguration.rememberMeManager()");
	       CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
	       cookieRememberMeManager.setCookie(rememberMeCookie());
	       //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
	       cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
	       return cookieRememberMeManager;
	 }
	 
	 /**
	  * 配置shiro对thymeleaf解析
	  */
	 @Bean
	 public ShiroDialect shiroDialect () {
		 
		 ShiroDialect shiroDialect = new ShiroDialect();
		
		 return shiroDialect;
	 }
	 
	 /**
	  * 无权限页面跳转,如果使用xml配置则不用配置
	  */
	 @Bean
	 public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
		 SimpleMappingExceptionResolver simpleMappingExceptionResolver = new SimpleMappingExceptionResolver();
		 Properties mapping = new Properties();
		 mapping.setProperty("UnauthorizedException", "/unauthor");
		 simpleMappingExceptionResolver.setExceptionMappings(mapping);
		 return simpleMappingExceptionResolver;
	 }
	 /**
		 * 验证码生成器;
		 * @return
		 */
		@Bean
		public Producer producer(){
			//System.out.println("ShiroConfiguration.captchaProducer()");
			DefaultKaptcha producer = new DefaultKaptcha();
			Properties properties = new Properties();
			
			/*
				kaptcha.border  是否有边框  默认为true  我们可以自己设置yes，no  
				kaptcha.border.color   边框颜色   默认为Color.BLACK  
				kaptcha.border.thickness  边框粗细度  默认为1  
				kaptcha.producer.impl   验证码生成器  默认为DefaultKaptcha  
				kaptcha.textproducer.impl   验证码文本生成器  默认为DefaultTextCreator  
				kaptcha.textproducer.char.string   验证码文本字符内容范围  默认为abcde2345678gfynmnpwx  
				kaptcha.textproducer.char.length   验证码文本字符长度  默认为5  
				kaptcha.textproducer.font.names    验证码文本字体样式  默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)  
				kaptcha.textproducer.font.size   验证码文本字符大小  默认为40  
				kaptcha.textproducer.font.color  验证码文本字符颜色  默认为Color.BLACK  
				kaptcha.textproducer.char.space  验证码文本字符间距  默认为2  
				kaptcha.noise.impl    验证码噪点生成对象  默认为DefaultNoise  
				kaptcha.noise.color   验证码噪点颜色   默认为Color.BLACK  
				kaptcha.obscurificator.impl   验证码样式引擎  默认为WaterRipple  
				kaptcha.word.impl   验证码文本字符渲染   默认为DefaultWordRenderer  
				kaptcha.background.impl   验证码背景生成器   默认为DefaultBackground  
				kaptcha.background.clear.from   验证码背景颜色渐进   默认为Color.LIGHT_GRAY  
				kaptcha.background.clear.to   验证码背景颜色渐进   默认为Color.WHITE  
				kaptcha.image.width   验证码图片宽度  默认为200  
				kaptcha.image.height  验证码图片高度  默认为50 
			 */
			
			// 是否有边框  默认为true  我们可以自己设置yes，no  
			properties.put("kaptcha.border","yes");
			
			//边框颜色   默认为Color.BLACK  
			properties.put("kaptcha.border.color","105,179,90");
			
			//字体颜色;
			properties.put("kaptcha.textproducer.font.color","blue");
			
			//验证码样式引擎  默认为WaterRipple  
			properties.put("kaptcha.obscurificator.impl","com.google.code.kaptcha.impl.ShadowGimpy");
			
			// 验证码图片宽度  默认为200  
			properties.put("kaptcha.image.width","145");
			
			//验证码图片高度  默认为50 
			properties.put("kaptcha.image.height","45");
			
			//验证码文本字符大小  默认为40  
			properties.put("kaptcha.textproducer.font.size","45");
			
			//存放在session中的key;
			properties.put("kaptcha.session.key","code");
			
			//产生字符的长度
			properties.put("kaptcha.textproducer.char.length","4");
			
			//文本字符字体
			properties.put("kaptcha.textproducer.font.names","宋体,楷体,微软雅黑");
			
			
			Config config = new Config(properties);
			producer.setConfig(config);
			return producer;
		}

	
}
